﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Algobox.JuicyLib.Arithmetic
{
    public class DateTimeMovingAverage
    {
        /// <summary>
        /// Create a new moving average calculator.
        /// </summary>
        /// <param name="windowSize">The maximum number of values to be considered
        /// by this moving average calculation.</param>
        /// <exception cref="ArgumentOutOfRangeException">If windowSize less than one.</exception>
        public DateTimeMovingAverage(TimeSpan windowSize)
        {
            if (windowSize <= TimeSpan.Zero)
                throw new ArgumentOutOfRangeException("WindowSize", windowSize, "Window size must be greater than zero.");

            Data = new Dictionary<DateTime, double>();
            WindowSize = windowSize;
        }

        bool isMature = false;
        public bool IsMature { get { return isMature; } }

        DateTime? startTime = null;

        Dictionary<DateTime, double> Data;

        TimeSpan WindowSize;

        double CurrentValue;

        public double Average { get { return CurrentValue; } }

        public string ToString() { return CurrentValue.ToString(); }

        /// <summary>
        /// Updates the moving average with its next value, and returns the updated average value.
        /// When IsMature is true and NextValue is called, a previous value will 'fall out' of the
        /// moving average.
        /// </summary>
        public double NextValue(DateTime timeStamp, double nextValue)
        {
            if (!isMature)
            {
                if (!startTime.HasValue)
                    startTime = timeStamp;

                if (timeStamp >= startTime.Value + WindowSize)
                    isMature = true;
            }

            Data[timeStamp] = nextValue;

            Data = Data.Where(elements => elements.Key > timeStamp - WindowSize).ToDictionary(item => item.Key, item => item.Value);

            CurrentValue = Data.Average(element => element.Value);

            return CurrentValue;
        }


        /// <summary>
        /// Clears any accumulated state and resets the calculator to its initial configuration.
        /// Calling this method is the equivalent of creating a new instance.
        /// </summary>
        public void Reset()
        {
            Data.Clear();
        }

        
    }





}
